using System;
using System.Diagnostics;


namespace XmlObjects
{

  /// <summary>
  /// Error codes raised by XmlObjects; these codes are embedded in XmlObjectExceptions
  /// </summary>
  public enum XmlObjectsError
  {
    ArrayOnSimpleField,
    AsElementUnsetOnArray,
    AttributeDoesNotExist,
    ElementDoesNotExist,
    ExplicitOnSpecialField,
    FieldDoesNotExist,
    FieldWithTypeAttributeName,
    InvalidFieldType,
    InvalidParseMethod,
    InvalidParsingString,
    InvalidTypeDefinition,
    InvalidTypeDefinitionRelationship,
    MethodDoesNotExist,
    MultipleFieldsWithSameName,
    MultipleRootsOnXmlDoc,
    NoEmptyConstructor,
    NoInnerText,
    RecursiveReference,
    UncompletedXmlDoc,
    UnexpectedXmlRoot,
    UnmatchingChildsField
  }





  /// <summary>
  /// Exception sent by the XmlObjectsLoader.
  /// Other exceptions are also possible, when no raised directly by the loader,
  ///   like IO Exceptions, etc.
  /// </summary>
  public class XmlObjectsException : Exception
  {
    /// <summary>
    /// Single constructor
    /// </summary>
    /// <param name="messageCode"></param>
    /// <param name="args"></param>
    public XmlObjectsException(XmlObjectsError messageCode, params object[] args)
      : base(String.Format(getErrorMessage(messageCode), args))
    {
      this.messageCode = messageCode;
    }



    /// <summary>
    /// Getter to access the message code causing the exception
    /// </summary>
    public XmlObjectsError Error
    {
      get { return messageCode; }
    }



    private XmlObjectsError messageCode;


    /// <summary>
    /// error messages associated to each XmlObjectsError code.
    /// Note that the static constructor of this class verifies if there are as many
    ///    messages as error codes
    /// </summary>
    private static string[] errorMessages = {
            "{0}.{1} is not an array, but {2} elements read from Xml",
            "{0}.{1} is an array, XmlField.AsElement cannot be unset",
            "Class '{0}' does not contain an attribute called '{1}'",
            "Class '{0}' does not contain an element called '{1}'",
            "{0}.{1} is defined as XmlField, but it is already an special class field",
            "Class '{0}' does not contain a field called '{1}'",
            "Class '{0}' defines an attribute with name '{1}', that is the type attribute name",
            "Invalid type: cannot set {0}.{1} with an instance of type {2}",
            "The Parse method of class '{0}' must return an instance of the same type",
            "Invalid content '{1}' for type '{0}'",
            "Invalid definition '{0}' for type '{1}': not found",
            "Invalid definition '{0}' for type '{1}': not properly related",
            "Class '{0}' does not contain a method called '{1}' (or the signature is not valid)",
            "{0} defines more than one field with name (case unsensitive) '{1}'",
            "Read '{0}' element, but this element was unexpected",
            "The class '{0}' does not define an empty constructor",
            "{0} cannot have an inner text",
            "'{1}' cannot be stored. It is referenced recursively by '{0}'",
            "Uncompleted XML document",
            "The XML root element is '{0}', but '{1}' was expected",
            "The childs field does not match all the found elements in type '{0}'"
        };


    /// <summary>
    /// Returns the error message associated to the given error code, with a
    ///   default message if the error code is invalid
    /// </summary>
    /// <param name="error"></param>
    /// <returns></returns>
    static string getErrorMessage(XmlObjectsError error)
    {
      int order = (int)error;
      return order >= errorMessages.Length ? "Unknown XmlObjects error" : errorMessages[order];
    }


    /// <summary>
    /// Simple verifier to check that the errorMessages and errorCodes have the same 
    ///   number of elements
    /// </summary>
    static XmlObjectsException()
    {
      Debug.Assert(Enum.GetValues(typeof(XmlObjectsError)).Length == errorMessages.Length);
    }
  }



}
